{
  "nbformat": 4,
  "nbformat_minor": 0,
  "metadata": {
    "colab": {
      "name": "save_and_load.ipynb",
      "provenance": [],
      "private_outputs": true,
      "collapsed_sections": [],
      "toc_visible": true
    },
    "kernelspec": {
      "display_name": "Python 3",
      "name": "python3"
    },
    "accelerator": "GPU"
  },
  "cells": [
    {
      "cell_type": "markdown",
      "metadata": {
        "colab_type": "text",
        "id": "g_nWetWWd_ns"
      },
      "source": [
        "##### Copyright 2019 The TensorFlow Authors."
      ]
    },
    {
      "cell_type": "code",
      "metadata": {
        "cellView": "form",
        "colab_type": "code",
        "id": "2pHVBk_seED1",
        "colab": {}
      },
      "source": [
        "#@title Licensed under the Apache License, Version 2.0 (the \"License\");\n",
        "# you may not use this file except in compliance with the License.\n",
        "# You may obtain a copy of the License at\n",
        "#\n",
        "# https://www.apache.org/licenses/LICENSE-2.0\n",
        "#\n",
        "# Unless required by applicable law or agreed to in writing, software\n",
        "# distributed under the License is distributed on an \"AS IS\" BASIS,\n",
        "# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n",
        "# See the License for the specific language governing permissions and\n",
        "# limitations under the License."
      ],
      "execution_count": 0,
      "outputs": []
    },
    {
      "cell_type": "code",
      "metadata": {
        "cellView": "form",
        "colab_type": "code",
        "id": "N_fMsQ-N8I7j",
        "colab": {}
      },
      "source": [
        "#@title MIT License\n",
        "#\n",
        "# Copyright (c) 2017 François Chollet\n",
        "#\n",
        "# Permission is hereby granted, free of charge, to any person obtaining a\n",
        "# copy of this software and associated documentation files (the \"Software\"),\n",
        "# to deal in the Software without restriction, including without limitation\n",
        "# the rights to use, copy, modify, merge, publish, distribute, sublicense,\n",
        "# and/or sell copies of the Software, and to permit persons to whom the\n",
        "# Software is furnished to do so, subject to the following conditions:\n",
        "#\n",
        "# The above copyright notice and this permission notice shall be included in\n",
        "# all copies or substantial portions of the Software.\n",
        "#\n",
        "# THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n",
        "# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n",
        "# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL\n",
        "# THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n",
        "# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\n",
        "# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER\n",
        "# DEALINGS IN THE SOFTWARE."
      ],
      "execution_count": 0,
      "outputs": []
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "colab_type": "text",
        "id": "pZJ3uY9O17VN"
      },
      "source": [
        "# Сохранение и загрузка моделей"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "colab_type": "text",
        "id": "M4Ata7_wMul1"
      },
      "source": [
        "<table class=\"tfo-notebook-buttons\" align=\"left\">\n",
        "  <td>\n",
        "    <a target=\"_blank\" href=\"https://www.tensorflow.org/tutorials/keras/save_and_load\"><img src=\"https://www.tensorflow.org/images/tf_logo_32px.png\" />Смотрите на TensorFlow.org</a>\n",
        "  </td>\n",
        "  <td>\n",
        "    <a target=\"_blank\" href=\"https://colab.research.google.com/github/tensorflow/docs/blob/master/site/ru/tutorials/keras/save_and_load.ipynb\"><img src=\"https://www.tensorflow.org/images/colab_logo_32px.png\" />Запустите в Google Colab</a>\n",
        "  </td>\n",
        "  <td>\n",
        "    <a target=\"_blank\" href=\"https://github.com/tensorflow/docs/blob/master/site/ru/tutorials/keras/save_and_load.ipynb\"><img src=\"https://www.tensorflow.org/images/GitHub-Mark-32px.png\" />Изучайте код на GitHub</a>\n",
        "  </td>\n",
        "  <td>\n",
        "    <a href=\"https://storage.googleapis.com/tensorflow_docs/docs/site/ru/tutorials/keras/save_and_load.ipynb\"><img src=\"https://www.tensorflow.org/images/download_logo_32px.png\" />Скачайте ноутбук</a>\n",
        "  </td>\n",
        "</table>"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "aM8euLg4l1bQ",
        "colab_type": "text"
      },
      "source": [
        "Note: Вся информация в этом разделе переведена с помощью русскоговорящего Tensorflow сообщества на общественных началах. Поскольку этот перевод не является официальным, мы не гарантируем что он на 100% аккуратен и соответствует [официальной документации на английском языке](https://www.tensorflow.org/?hl=en). Если у вас есть предложение как исправить этот перевод, мы будем очень рады увидеть pull request в [tensorflow/docs](https://github.com/tensorflow/docs) репозиторий GitHub. Если вы хотите помочь сделать документацию по Tensorflow лучше (сделать сам перевод или проверить перевод подготовленный кем-то другим), напишите нам на [docs-ru@tensorflow.org list](https://groups.google.com/a/tensorflow.org/forum/#!forum/docs-ru)."
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "colab_type": "text",
        "id": "mBdde4YJeJKF"
      },
      "source": [
        "Прогресс обучения модели может быть сохранен во время и после обучения. Это значит, что можно продолжить обучение с того места, где оно было остановлено, что позволит избежать длительных безостановочных сессий. Сохранение также значит то, что вы можете поделиться своей моделью с другими и они смогут воспроизвести вашу работу. При публикации исследовательских моделей и техник большинство практиков машинного обучения делятся:\n",
        "\n",
        "* кодом необходимым для создания модели, и\n",
        "* обученными весами, или параметрами модели\n",
        "\n",
        "Публикация этих данных помогает другим понять как работает модель и попробовать ее самостоятельно с новыми данными.\n",
        "\n",
        "Предупреждение: Будьте осторожны с ненадежным кодом — модели TensorFlow являются кодом. См. [Безопасное использование TensorFlow](https://github.com/tensorflow/tensorflow/blob/master/SECURITY.md) для подробностей.\n",
        "\n",
        "### Варианты\n",
        "\n",
        "Существуют различные способы сохранения моделей Tensorflow - зависит от API которое ты используешь. Это руководство использует [tf.keras](https://www.tensorflow.org/guide/keras) высокоуровневый API для построения и обучения моделей в TensorFlow. Для остальных подходов см. руководство TensorFlow [сохранение и восстановление](https://www.tensorflow.org/guide/saved_model) или [Сохранение в eager](https://www.tensorflow.org/guide/eager#object-based_saving)."
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "colab_type": "text",
        "id": "xCUREq7WXgvg"
      },
      "source": [
        "## Установка\n",
        "\n",
        "### Инсталляция и импорт"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "colab_type": "text",
        "id": "7l0MiTOrXtNv"
      },
      "source": [
        "Установим и импортируем TensorFlow и зависимые библиотеки:"
      ]
    },
    {
      "cell_type": "code",
      "metadata": {
        "colab_type": "code",
        "id": "RzIOVSdnMYyO",
        "colab": {}
      },
      "source": [
        "try:\n",
        "  # %tensorflow_version существует только в Colab.\n",
        "  %tensorflow_version 2.x\n",
        "except Exception:\n",
        "  pass\n",
        "\n",
        "!pip install pyyaml h5py  # Требуется для сохранения модели в формате HDF5"
      ],
      "execution_count": 0,
      "outputs": []
    },
    {
      "cell_type": "code",
      "metadata": {
        "colab_type": "code",
        "id": "7Nm7Tyb-gRt-",
        "colab": {}
      },
      "source": [
        "from __future__ import absolute_import, division, print_function, unicode_literals\n",
        "\n",
        "import os\n",
        "\n",
        "import tensorflow as tf\n",
        "from tensorflow import keras\n",
        "\n",
        "print(tf.version.VERSION)"
      ],
      "execution_count": 0,
      "outputs": []
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "colab_type": "text",
        "id": "SbGsznErXWt6"
      },
      "source": [
        "### Получите набор данных\n",
        "\n",
        "Для демонстрации того как сохранять и загружать веса вы используете [датасет MNIST](http://yann.lecun.com/exdb/mnist/). Для ускорения запусков используйте только первые 1000 примеров:"
      ]
    },
    {
      "cell_type": "code",
      "metadata": {
        "colab_type": "code",
        "id": "9rGfFwE9XVwz",
        "colab": {}
      },
      "source": [
        "(train_images, train_labels), (test_images, test_labels) = tf.keras.datasets.mnist.load_data()\n",
        "\n",
        "train_labels = train_labels[:1000]\n",
        "test_labels = test_labels[:1000]\n",
        "\n",
        "train_images = train_images[:1000].reshape(-1, 28 * 28) / 255.0\n",
        "test_images = test_images[:1000].reshape(-1, 28 * 28) / 255.0"
      ],
      "execution_count": 0,
      "outputs": []
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "colab_type": "text",
        "id": "anG3iVoXyZGI"
      },
      "source": [
        "### Определите модель"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "colab_type": "text",
        "id": "wynsOBfby0Pa"
      },
      "source": [
        "Начните с построения простой последовательной модели:"
      ]
    },
    {
      "cell_type": "code",
      "metadata": {
        "colab_type": "code",
        "id": "0HZbJIjxyX1S",
        "colab": {}
      },
      "source": [
        "# Определим простую последовательную модель\n",
        "def create_model():\n",
        "  model = tf.keras.models.Sequential([\n",
        "    keras.layers.Dense(512, activation='relu', input_shape=(784,)),\n",
        "    keras.layers.Dropout(0.2),\n",
        "    keras.layers.Dense(10, activation='softmax')\n",
        "  ])\n",
        "\n",
        "  model.compile(optimizer='adam',\n",
        "                loss='sparse_categorical_crossentropy',\n",
        "                metrics=['accuracy'])\n",
        "\n",
        "  return model\n",
        "\n",
        "# Создадим экземпляр базовой модели\n",
        "model = create_model()\n",
        "\n",
        "# Распечатаем архитектуру модели\n",
        "model.summary()"
      ],
      "execution_count": 0,
      "outputs": []
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "colab_type": "text",
        "id": "soDE0W_KH8rG"
      },
      "source": [
        "## Сохраните контрольные точки во время обучения"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "colab_type": "text",
        "id": "mRyd5qQQIXZm"
      },
      "source": [
        "Вы можете использовать обученную модель без повторного ее обучения, или продолжить обучение с того места где вы остановились, в случае если процесс обучения был прерван. Коллбек `tf.keras.callbacks.ModelCheckpoint` позволяет непрерывно сохранять модель как *во время* так и *по окончанию* обучения\n",
        "\n",
        "### Использование коллбека контрольной точки (checkpoint callback)\n",
        "\n",
        "Создайте коллбек `tf.keras.callbacks.ModelCheckpoint` который сохраняет веса только во время обучения:"
      ]
    },
    {
      "cell_type": "code",
      "metadata": {
        "colab_type": "code",
        "id": "IFPuhwntH8VH",
        "colab": {}
      },
      "source": [
        "checkpoint_path = \"training_1/cp.ckpt\"\n",
        "checkpoint_dir = os.path.dirname(checkpoint_path)\n",
        "\n",
        "# Создаем коллбек сохраняющий веса модели\n",
        "cp_callback = tf.keras.callbacks.ModelCheckpoint(filepath=checkpoint_path,\n",
        "                                                 save_weights_only=True,\n",
        "                                                 verbose=1)\n",
        "\n",
        "# Обучаем модель с новым коллбеком\n",
        "model.fit(train_images, \n",
        "          train_labels,  \n",
        "          epochs=10,\n",
        "          validation_data=(test_images,test_labels),\n",
        "          callbacks=[cp_callback])  # Pass callback to training\n",
        "\n",
        "# Это может генерировать предупреждения относящиеся к сохранению состояния оптимизатора.\n",
        "# Эти предупреждения (и подобные предупреждения в этом уроке)\n",
        "# используются для предотвращения устаревшего использования и могут быть проигнорированы."
      ],
      "execution_count": 0,
      "outputs": []
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "colab_type": "text",
        "id": "rlM-sgyJO084"
      },
      "source": [
        "Это создаст единый набор файлов контрольных точек TensorFlow который обновляется в конце каждой эпохи:"
      ]
    },
    {
      "cell_type": "code",
      "metadata": {
        "colab_type": "code",
        "id": "gXG5FVKFOVQ3",
        "colab": {}
      },
      "source": [
        "!ls {checkpoint_dir}"
      ],
      "execution_count": 0,
      "outputs": []
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "colab_type": "text",
        "id": "wlRN_f56Pqa9"
      },
      "source": [
        "Создайте новую, необученную модель. При восстановлении модели только из весов, у вас должна быть модель с такой же архитектурой, как и восстанавливаемая. Так как архитектура модели такая же вы можете поделиться весами несмотря на то что это другой *экземпляр* модели.\n",
        "\n",
        "Сейчас восстановите свежую, необученную модель и оцените ее на тестовом наборе. Неподготовленная модель будет работать на уровне угадывания (точность ~ 10%):"
      ]
    },
    {
      "cell_type": "code",
      "metadata": {
        "colab_type": "code",
        "id": "Fp5gbuiaPqCT",
        "colab": {}
      },
      "source": [
        "# Создайте экземпляр базовой модели\n",
        "model = create_model()\n",
        "\n",
        "# Оцените модель\n",
        "loss, acc = model.evaluate(test_images,  test_labels, verbose=2)\n",
        "print(\"Untrained model, accuracy: {:5.2f}%\".format(100*acc))"
      ],
      "execution_count": 0,
      "outputs": []
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "colab_type": "text",
        "id": "1DTKpZssRSo3"
      },
      "source": [
        "Затем загрузите веса из чекпоинта и оцените снова:"
      ]
    },
    {
      "cell_type": "code",
      "metadata": {
        "colab_type": "code",
        "id": "2IZxbwiRRSD2",
        "colab": {}
      },
      "source": [
        "# Загрузим веса\n",
        "model.load_weights(checkpoint_path)\n",
        "\n",
        "# Оценим модель снова\n",
        "loss,acc = model.evaluate(test_images,  test_labels, verbose=2)\n",
        "print(\"Restored model, accuracy: {:5.2f}%\".format(100*acc))"
      ],
      "execution_count": 0,
      "outputs": []
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "colab_type": "text",
        "id": "bpAbKkAyVPV8"
      },
      "source": [
        "### Параметры коллбека контрольной точки\n",
        "\n",
        "У коллбека есть несколько параметров которые задают контрольным точкам уникальные имена, а также корректируют частоту создания контрольных точек.\n",
        "\n",
        "Обучите новую модель и сохраните по разному названные чекпоинты каждые пять эпох:"
      ]
    },
    {
      "cell_type": "code",
      "metadata": {
        "colab_type": "code",
        "id": "mQF_dlgIVOvq",
        "colab": {}
      },
      "source": [
        "# Добавим эпоху в имя файла (uses `str.format`)\n",
        "checkpoint_path = \"training_2/cp-{epoch:04d}.ckpt\"\n",
        "checkpoint_dir = os.path.dirname(checkpoint_path)\n",
        "\n",
        "# Создадим коллбек сохраняющий веса модели каждые 5 эпох\n",
        "cp_callback = tf.keras.callbacks.ModelCheckpoint(\n",
        "    filepath=checkpoint_path, \n",
        "    verbose=1, \n",
        "    save_weights_only=True,\n",
        "    period=5)\n",
        "\n",
        "# Создадим новый экземпляр модели\n",
        "model = create_model()\n",
        "\n",
        "# Сохраним веса используя формат `checkpoint_path` format\n",
        "model.save_weights(checkpoint_path.format(epoch=0))\n",
        "\n",
        "# Обучим модель с новым коллбеком\n",
        "model.fit(train_images, \n",
        "              train_labels,\n",
        "              epochs=50, \n",
        "              callbacks=[cp_callback],\n",
        "              validation_data=(test_images,test_labels),\n",
        "              verbose=0)"
      ],
      "execution_count": 0,
      "outputs": []
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "colab_type": "text",
        "id": "1zFrKTjjavWI"
      },
      "source": [
        "Сейчас посмотрите на получившиеся чекпоинты и выберите последний:"
      ]
    },
    {
      "cell_type": "code",
      "metadata": {
        "colab_type": "code",
        "id": "p64q3-V4sXt0",
        "colab": {}
      },
      "source": [
        "! ls {checkpoint_dir}"
      ],
      "execution_count": 0,
      "outputs": []
    },
    {
      "cell_type": "code",
      "metadata": {
        "colab_type": "code",
        "id": "1AN_fnuyR41H",
        "colab": {}
      },
      "source": [
        "latest = tf.train.latest_checkpoint(checkpoint_dir)\n",
        "latest"
      ],
      "execution_count": 0,
      "outputs": []
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "colab_type": "text",
        "id": "Zk2ciGbKg561"
      },
      "source": [
        "Замечание: базовый формат tensorflow сохраняет только 5 последних контрольных точек.\n",
        "\n",
        "Для проверки сбросим модель и загрузим последний чекпоинт:"
      ]
    },
    {
      "cell_type": "code",
      "metadata": {
        "colab_type": "code",
        "id": "3M04jyK-H3QK",
        "colab": {}
      },
      "source": [
        "# Создадим новый экземпляр модели\n",
        "model = create_model()\n",
        "\n",
        "# Загрузим предварительно сохраненные веса\n",
        "model.load_weights(latest)\n",
        "\n",
        "# Заново оценим модель\n",
        "loss, acc = model.evaluate(test_images,  test_labels, verbose=2)\n",
        "print(\"Restored model, accuracy: {:5.2f}%\".format(100*acc))"
      ],
      "execution_count": 0,
      "outputs": []
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "colab_type": "text",
        "id": "c2OxsJOTHxia"
      },
      "source": [
        "## Что это за файлы?"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "colab_type": "text",
        "id": "JtdYhvWnH2ib"
      },
      "source": [
        "Приведенный выше код хранит веса в коллекции [checkpoint](https://www.tensorflow.org/guide/saved_model#save_and_restore_variables)-отформатированных файлов, которые содержат только обученные веса в двоичном формате. Чекпоинты содержат:\n",
        "* Один или несколько разделов (shards) которые содержат веса вашей модели.\n",
        "* Индексный файл который указывает какие веса содрержатся в каждом из разделов.\n",
        "\n",
        "Если Вы обучаете модель только на одной машине, у Вас будет один раздел с суффиксом: `.data-00000-of-00001`"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "colab_type": "text",
        "id": "S_FA-ZvxuXQV"
      },
      "source": [
        "## Сохраните веса вручную\n",
        "\n",
        "Вы уже видели как загрузить веса в модель. Ручное их сохранение так же просто с использованием метода `Model.save_weights`. По умолчанию `tf.keras` и `save_weights` в частности используют формат [чекпоинтов](../../guide/keras/checkpoints) TensorFlow с расширением `.ckpt` (сохранение в [HDF5](https://js.tensorflow.org/tutorials/import-keras.html) с раширением `.h5` рассмотренно в материале [Сохранение и сериализация моделей](../../guide/keras/save_and_serialize#weights-only_saving_in_savedmodel_format) guide):"
      ]
    },
    {
      "cell_type": "code",
      "metadata": {
        "colab_type": "code",
        "id": "R7W5plyZ-u9X",
        "colab": {}
      },
      "source": [
        "# Сохраним веса\n",
        "model.save_weights('./checkpoints/my_checkpoint')\n",
        "\n",
        "# Создадим новый экземпляр модели\n",
        "model = create_model()\n",
        "\n",
        "# Восстановим веса\n",
        "model.load_weights('./checkpoints/my_checkpoint')\n",
        "\n",
        "# Оценим модель\n",
        "loss,acc = model.evaluate(test_images,  test_labels, verbose=2)\n",
        "print(\"Restored model, accuracy: {:5.2f}%\".format(100*acc))"
      ],
      "execution_count": 0,
      "outputs": []
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "colab_type": "text",
        "id": "kOGlxPRBEvV1"
      },
      "source": [
        "## Сохраните всю модель\n",
        "\n",
        "Модель и оптимизатор могут быть сохранены в файл который содержит и их состояние (веса и переменные) и конфигурацию модели. Это позволит Вам экспортировать модель так, чтобы она могла быть использована без доступа к исходному коду Python. Поскольку состояние оптимизатора восстановлено, вы можете продолжить обучение в точности с того места где остановились.\n",
        "\n",
        "Сохранение полностью функциональной модели очень полезно - вы можете загрузить его в TensorFlow.js ([HDF5](https://js.tensorflow.org/tutorials/import-keras.html), [Сохраненная модель](https://js.tensorflow.org/tutorials/import-saved-model.html)) и затем обучить и запустить ее в веб-браузере, или сконвертировать для исполнения в мобильных устройствах с использованием TensorFlow Lite ([HDF5](https://www.tensorflow.org/lite/convert/python_api#exporting_a_tfkeras_file_), [Сохраненная модель](https://www.tensorflow.org/lite/convert/python_api#exporting_a_savedmodel_))"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "colab_type": "text",
        "id": "SkGwf-50zLNn"
      },
      "source": [
        "### Сохраните модель в файл HDF5\n",
        "\n",
        "Keras также обеспечивает базовый формат сохранения с использованием стандарта [HDF5](https://en.wikipedia.org/wiki/Hierarchical_Data_Format). Для наших целей сохраненная модель может быть рассмотрена как единый двоичный blob:"
      ]
    },
    {
      "cell_type": "code",
      "metadata": {
        "colab_type": "code",
        "id": "m2dkmJVCGUia",
        "colab": {}
      },
      "source": [
        "# Создадим новый экземпляр модели\n",
        "model = create_model()\n",
        "\n",
        "# Обучим модель\n",
        "model.fit(train_images, train_labels, epochs=5)\n",
        "\n",
        "# Сохраним всю модель в  HDF5 файл\n",
        "model.save('my_model.h5')"
      ],
      "execution_count": 0,
      "outputs": []
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "colab_type": "text",
        "id": "GWmttMOqS68S"
      },
      "source": [
        "Сейчас восстановим модель с того файла:"
      ]
    },
    {
      "cell_type": "code",
      "metadata": {
        "colab_type": "code",
        "id": "5NDMO_7kS6Do",
        "colab": {}
      },
      "source": [
        "# Восстановим в точности ту же модель, включая веса и оптимизатор\n",
        "new_model = keras.models.load_model('my_model.h5')\n",
        "\n",
        "# Покажем архитектуру модели\n",
        "new_model.summary()"
      ],
      "execution_count": 0,
      "outputs": []
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "colab_type": "text",
        "id": "JXQpbTicTBwt"
      },
      "source": [
        "Проверим ее точность:"
      ]
    },
    {
      "cell_type": "code",
      "metadata": {
        "colab_type": "code",
        "id": "jwEaj9DnTCVA",
        "colab": {}
      },
      "source": [
        "loss, acc = new_model.evaluate(test_images,  test_labels, verbose=2)\n",
        "print(\"Точность восстановленной модели: {:5.2f}%\".format(100*acc))"
      ],
      "execution_count": 0,
      "outputs": []
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "colab_type": "text",
        "id": "dGXqd4wWJl8O"
      },
      "source": [
        "Эта техника сохраняет все:\n",
        "\n",
        "* Значения весов\n",
        "* Конфигурацию модели (архитектуру)\n",
        "* Конфигурацию оптимизатора\n",
        "\n",
        "Keras сохраняет модели путем проверки архитектуры. Сейчас Keras не может сохранять оптимизаторы TensorFlow (из `tf.train`). При их использовании вам нужно перекомпилировать модель после загрузки и вы потеряете текущее состояние оптимизатора.\n"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "colab_type": "text",
        "id": "kPyhgcoVzqUB"
      },
      "source": [
        "### Как и `saved_model`"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "colab_type": "text",
        "id": "LtcN4VIb7JkK"
      },
      "source": [
        "Предупреждение: Этот метод сохранения модели `tf.keras` экспериментальный и может измениться в будущих версиях.\n",
        "\n",
        "Постройте новую модель и затем обучите ее:"
      ]
    },
    {
      "cell_type": "code",
      "metadata": {
        "colab_type": "code",
        "id": "sI1YvCDFzpl3",
        "colab": {}
      },
      "source": [
        "model = create_model()\n",
        "\n",
        "model.fit(train_images, train_labels, epochs=5)"
      ],
      "execution_count": 0,
      "outputs": []
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "colab_type": "text",
        "id": "iUvT_3qE8hV5"
      },
      "source": [
        "Создайте `saved_model`, и поместите ее в папку с временной меткой с `tf.keras.experimental.export_saved_model`:"
      ]
    },
    {
      "cell_type": "code",
      "metadata": {
        "colab_type": "code",
        "id": "sq8fPglI1RWA",
        "colab": {}
      },
      "source": [
        "import time\n",
        "saved_model_path = \"./saved_models/{}\".format(int(time.time()))\n",
        "\n",
        "tf.keras.experimental.export_saved_model(model, saved_model_path)\n",
        "saved_model_path"
      ],
      "execution_count": 0,
      "outputs": []
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "colab_type": "text",
        "id": "MjpmyPfh8-1n"
      },
      "source": [
        "Выведите на экран ваши сохраненные модели:"
      ]
    },
    {
      "cell_type": "code",
      "metadata": {
        "colab_type": "code",
        "id": "ZtOvxA7V0iTv",
        "colab": {}
      },
      "source": [
        "!ls saved_models/"
      ],
      "execution_count": 0,
      "outputs": []
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "colab_type": "text",
        "id": "B7qfpvpY9HCe"
      },
      "source": [
        "Загрузите свежую модель Keras из сохраненной модели:"
      ]
    },
    {
      "cell_type": "code",
      "metadata": {
        "colab_type": "code",
        "id": "0YofwHdN0pxa",
        "colab": {}
      },
      "source": [
        "new_model = tf.keras.experimental.load_from_saved_model(saved_model_path)\n",
        "\n",
        "# Проверим ее архитектуру\n",
        "new_model.summary()"
      ],
      "execution_count": 0,
      "outputs": []
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "colab_type": "text",
        "id": "uWwgNaz19TH2"
      },
      "source": [
        "Запустите предсказания с восстановленной моделью:"
      ]
    },
    {
      "cell_type": "code",
      "metadata": {
        "colab_type": "code",
        "id": "Yh5Mu0yOgE5J",
        "colab": {}
      },
      "source": [
        "model.predict(test_images).shape"
      ],
      "execution_count": 0,
      "outputs": []
    },
    {
      "cell_type": "code",
      "metadata": {
        "colab_type": "code",
        "id": "Pc9e6G6w1AWG",
        "colab": {}
      },
      "source": [
        "# Модель должна быть скомпилирована перед использованием.\n",
        "# Этот шаг не требуется если сохраненная модель только разворачивается.\n",
        "\n",
        "new_model.compile(optimizer=model.optimizer,  #Оставляем загруженный оптимизатор\n",
        "                  loss='sparse_categorical_crossentropy', \n",
        "                  metrics=['accuracy'])\n",
        "\n",
        "# Evaluate the restored model\n",
        "loss, acc = new_model.evaluate(test_images,  test_labels, verbose=2)\n",
        "print(\"Точность восстановленной модели: {:5.2f}%\".format(100*acc))"
      ],
      "execution_count": 0,
      "outputs": []
    }
  ]
}